package vn.edu.ptithcm.pim.controller;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.validation.BindException;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.support.StringMultipartFileEditor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;

import vn.edu.ptithcm.pim.constant.Constants;
import vn.edu.ptithcm.pim.constant.Functions;
import vn.edu.ptithcm.pim.constant.TaskStatuses;
import vn.edu.ptithcm.pim.constant.UrlConstants;
import vn.edu.ptithcm.pim.dom.Application;
import vn.edu.ptithcm.pim.dom.Employee;
import vn.edu.ptithcm.pim.dom.EmployeeFunctionInProject;
import vn.edu.ptithcm.pim.dom.EmployeeFunctionInProjectId;
import vn.edu.ptithcm.pim.dom.Group;
import vn.edu.ptithcm.pim.dom.Project;
import vn.edu.ptithcm.pim.dom.Resource;
import vn.edu.ptithcm.pim.dom.Task;
import vn.edu.ptithcm.pim.dom.TaskLog;
import vn.edu.ptithcm.pim.service.CustomerService;
import vn.edu.ptithcm.pim.service.EmployeeFunctionInProjectService;
import vn.edu.ptithcm.pim.service.FunctionService;
import vn.edu.ptithcm.pim.service.GroupService;
import vn.edu.ptithcm.pim.service.ProjectService;
import vn.edu.ptithcm.pim.service.ProjectStatusService;
import vn.edu.ptithcm.pim.service.ResourceService;
import vn.edu.ptithcm.pim.service.TaskLogService;
import vn.edu.ptithcm.pim.service.TaskService;
import vn.edu.ptithcm.pim.service.TaskStatusService;
import vn.edu.ptithcm.pim.service.UserService;
import vn.edu.ptithcm.pim.util.FileUtil;
import vn.edu.ptithcm.pim.util.ParamUtil;
import vn.edu.ptithcm.pim.util.PimUtil;

@SuppressWarnings("deprecation")
public class HandleProjectController extends SimpleFormController {
	private EmployeeFunctionInProjectService employeeFunctionInProjectService;
	private ProjectService projectService;
	private CustomerService customerService;
	private GroupService groupService;
	private UserService userService;
	private ProjectStatusService projectStatusService;
	private TaskService taskService;
	private ResourceService resourceService;
	private TaskLogService taskLogService;
	private TaskStatusService taskStatusService;
	private FunctionService functionService;

	Logger log = Logger.getLogger(HandleProjectController.class);

	public HandleProjectController() {
		super();
		setSessionForm(true);
		setCommandName("project");
		setCommandClass(Project.class);
		setFormView(UrlConstants.HANDLE_PROJECT_URL);
		setSuccessView(UrlConstants.HANDLE_PROJECT_URL);
	}

	@Override
	protected Object formBackingObject(HttpServletRequest request)
			throws Exception {
		Project project = null;
		int pnum = ParamUtil.getInteger(request, "pnum", 0);
		project = projectService.findByNumber(pnum);
		if (project == null) {
			project = new Project();
		}
		return project;
	}

	@Override
	public void initBinder(HttpServletRequest request,
			ServletRequestDataBinder binder) throws Exception {
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		binder.registerCustomEditor(Date.class, new CustomDateEditor(
				dateFormat, true));
		if (request instanceof MultipartHttpServletRequest) {
			binder.registerCustomEditor(String.class,
					new StringMultipartFileEditor());
		}
	}

	@Override
	protected ModelAndView onSubmit(HttpServletRequest request,
			HttpServletResponse response, Object command, BindException errors)
			throws Exception {

		Project informProject = (Project) command;
		String cmd = ParamUtil.getString(request, Constants.CMD, "");
		String logourl = FileUtil.transferTo(request, "logourl",
				Constants.UPLOADED_FILE_FOLDER);

		if (!logourl.isEmpty()) {
			informProject.setLogourl(logourl);
		} else if (Constants.EDIT.equals(cmd)) {
			int projectNumber = informProject.getNumber();
			Project inDBProject = projectService.findByNumber(projectNumber);
			informProject.setLogourl(inDBProject.getLogourl());
		}

		if (Constants.EDIT.equals(cmd)) {
			projectService.saveOrUpdate(informProject);
			request.setAttribute("editOK", true);
			log.info("edited");

		} else if (Constants.ADD.equals(cmd)) {
			informProject.setNumber(PimUtil.generate(100, 1000,
					projectService.getAllNumbers()));

			projectService.save(informProject);

			Project savedProject = projectService.findByNumber(informProject
					.getNumber());

			if (savedProject != null) {
				Long groupId = informProject.getGroup().getGroupid();
				Group group = groupService.findById(groupId);

				Employee employee = group.getEmployee();
				EmployeeFunctionInProject efip = new EmployeeFunctionInProject();
				EmployeeFunctionInProjectId id = new EmployeeFunctionInProjectId(
						Functions.GL, savedProject.getProjectid().longValue(),
						employee.getEmployeeid().longValue());
				efip.setId(id);
				efip.setProject(savedProject);
				employeeFunctionInProjectService.save(efip);
				request.setAttribute("addOK", true);
				log.debug("added");

				String type = ParamUtil.getString(request, "type", "");

				if ("copy".equals(type)) {
					log.info("copy");
					Date date = new Date();
					int copyProjectNumber = ParamUtil.getInteger(request,
							"copyProject", 0);

					request.setAttribute("copyProjectNumber", copyProjectNumber);
					request.setAttribute("type", type);

					Project copyProject = projectService
							.findByNumber(copyProjectNumber);

					saveCopyProject(savedProject, copyProject,
							userService.getVisa(userService
									.getCurrentLogin(request)), date);
				}

			}
		}
		return showForm(request, response, errors);
	}

	@Override
	protected ModelAndView showForm(HttpServletRequest request,
			HttpServletResponse response, BindException errors)
			throws Exception {
		if (userService.isSignedIn(request)) {
			Map<String, Object> bean = new HashMap<String, Object>();
			String loginName = userService.getCurrentLogin(request);
			bean.put("user", userService.findByLoginName(loginName));
			bean.put("isSigned", true);
			bean.put("isAdmin", userService.isAdmin(loginName));
			bean.put(Constants.LOGIN_NAME, loginName);
			bean.put(Constants.USER_NAME, userService.getUsername(loginName));
			bean.put("customers", customerService.getAll());
			bean.put("projects", projectService.getAll());
			bean.put("groups", groupService.getAll());
			bean.put("statuses", projectStatusService.getAll());

			@SuppressWarnings("unchecked")
			List<Application> applications = userService
					.getApplications(loginName);

			String selectedPage = "";
			String viewURL = request.getRequestURI();
			for (Application p : applications) {
				String friendlyUrl = p.getFriendlyurl();
				if (viewURL.indexOf(friendlyUrl) != -1) {
					selectedPage = friendlyUrl;
					break;
				}
			}

			bean.put("selectedPage", selectedPage);
			bean.put("applications", applications);

			String cmd = ParamUtil.getString(request, Constants.CMD, "");
			bean.put(Constants.CMD, cmd);

			String returnToFullPageURL = ParamUtil.getString(request,
					Constants.RETURN_TO_FULL_PAGE_URL, "");

			if (returnToFullPageURL.isEmpty()) {
				returnToFullPageURL = request.getHeader("referer");
			}
			bean.put(Constants.RETURN_TO_FULL_PAGE_URL, returnToFullPageURL);

			request.setAttribute("bean", bean);
		} else {
			String cmd = ParamUtil.getString(request, Constants.CMD, "");
			String redirectLink = "";
			if (Constants.ADD.equals(cmd)) {
				redirectLink = UrlConstants.HANDLE_PROJECT_URL
						+ UrlConstants.HTM;
			} else if (Constants.EDIT.equals(cmd)) {
				int pnum = ParamUtil.getInteger(request, "pnum", 0);
				redirectLink = UrlConstants.HANDLE_PROJECT_URL
						+ UrlConstants.HTM + "?pnum=" + pnum;
			}

			request.getSession().setAttribute("redirectLink", redirectLink);
			response.sendRedirect(UrlConstants.HOME_PAGE_URL + UrlConstants.HTM);
		}
		return super.showForm(request, response, errors);
	}

	public ProjectService getProjectService() {
		return projectService;
	}

	public void setProjectService(ProjectService projectService) {
		this.projectService = projectService;
	}

	public CustomerService getCustomerService() {
		return customerService;
	}

	public void setCustomerService(CustomerService customerService) {
		this.customerService = customerService;
	}

	public GroupService getGroupService() {
		return groupService;
	}

	public void setGroupService(GroupService groupService) {
		this.groupService = groupService;
	}

	public ProjectStatusService getProjectStatusService() {
		return projectStatusService;
	}

	public void setProjectStatusService(
			ProjectStatusService projectStatusService) {
		this.projectStatusService = projectStatusService;
	}

	public UserService getUserService() {
		return userService;
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	public EmployeeFunctionInProjectService getEmployeeFunctionInProjectService() {
		return employeeFunctionInProjectService;
	}

	public void setEmployeeFunctionInProjectService(
			EmployeeFunctionInProjectService employeeFunctionInProjectService) {
		this.employeeFunctionInProjectService = employeeFunctionInProjectService;
	}

	/**
	 * @return the taskService
	 */
	public TaskService getTaskService() {
		return taskService;
	}

	/**
	 * @param taskService
	 *            the taskService to set
	 */
	public void setTaskService(TaskService taskService) {
		this.taskService = taskService;
	}

	/**
	 * @return the resourceService
	 */
	public ResourceService getResourceService() {
		return resourceService;
	}

	/**
	 * @param resourceService
	 *            the resourceService to set
	 */
	public void setResourceService(ResourceService resourceService) {
		this.resourceService = resourceService;
	}

	/**
	 * @return the taskLogService
	 */
	public TaskLogService getTaskLogService() {
		return taskLogService;
	}

	/**
	 * @param taskLogService
	 *            the taskLogService to set
	 */
	public void setTaskLogService(TaskLogService taskLogService) {
		this.taskLogService = taskLogService;
	}

	/**
	 * @return the taskStatusService
	 */
	public TaskStatusService getTaskStatusService() {
		return taskStatusService;
	}

	/**
	 * @param taskStatusService
	 *            the taskStatusService to set
	 */
	public void setTaskStatusService(TaskStatusService taskStatusService) {
		this.taskStatusService = taskStatusService;
	}

	/**
	 * @return the functionService
	 */
	public FunctionService getFunctionService() {
		return functionService;
	}

	/**
	 * @param functionService
	 *            the functionService to set
	 */
	public void setFunctionService(FunctionService functionService) {
		this.functionService = functionService;
	}

	private Task saveTask(Project project, Task copyTask, String visa, Date date) {

		String tcode = "";
		int n = taskService.getNumberOfItems(project.getProjectid());
		if (n == 0) {
			tcode = String.valueOf(project.getNumber()) + "1";
		} else {
			long maxId = taskService.getMaximumId(project.getProjectid());
			Task t = taskService.findById(new Long(maxId));

			tcode = String.valueOf(project.getNumber())
					+ String.valueOf(Integer.valueOf(StringUtils
							.substringAfter(t.getCode(),
									String.valueOf(project.getNumber()))) + 1);
		}

		Task task = new Task();

		task.copyTask(copyTask);

		task.setProject(project);
		task.setCode(tcode);
		task.setReporter(visa);

		task.setCreatedtime(date);
		task.setLastchanged(date);
		task.setStarttime(date);

		task.setAssignedto("");
		task.setMonitoredby("");
		task.setPhase("");

		task.setTaskStatus(taskStatusService
				.findById(new Long(TaskStatuses.NEW)));

		taskService.save(task);

		log.info("saved task " + tcode);

		Task savedTask = taskService.findByCode(task.getCode());

		if (savedTask != null) {

			TaskLog taskLog = new TaskLog();
			taskLog.setTask(savedTask);

			taskLog.setTime(date);

			taskLog.setField("Created");
			taskLog.setChange("Created");
			taskLog.setVisa(visa);
			taskLogService.save(taskLog);

			List<Resource> resources = resourceService.findByTask(copyTask
					.getTaskid());

			for (Resource resource : resources) {
				Resource res = new Resource();

				res.copyResource(resource);

				res.setAuthor(visa);
				res.setCreatedAt(date);
				res.setLastUpdated(date);
				res.setSubjectId(savedTask.getTaskid());
				res.setUpdatedBy(visa);

				resourceService.save(res);
			}
			return savedTask;
		}
		return null;
	}

	private Task saveTaskRecursion(Project project, Task copyTask, String visa,
			Date date) {
		Task task = saveTask(project, copyTask, visa, date);
		if (task == null || copyTask.getTasksForTaskchildid().size() == 0) {
			return task;
		} else {
			Set<Task> taskChilds = copyTask.getTasksForTaskchildid();

			for (Task child : taskChilds) {
				Task taskChild = saveTaskRecursion(project, child, visa, date);
				if (taskChild != null) {
					task.getTasksForTaskchildid().add(taskChild);
					taskService.saveOrUpdate(task);
				}
			}
		}
		return task;
	}

	@SuppressWarnings("unchecked")
	private void saveCopyProject(Project newProject, Project copyProject,
			String visa, Date date) {

		// copy tasks
		List<Task> tasks = taskService.getAllTasksForCopyProject(copyProject
				.getProjectid());

		for (Task copyTask : tasks) {
			saveTaskRecursion(newProject, copyTask, visa, date);
		}

		// copy documents
		List<Resource> resources = resourceService.findByProject(copyProject
				.getProjectid());

		for (Resource resource : resources) {
			Resource res = new Resource();

			res.copyResource(resource);

			res.setAuthor(visa);
			res.setCreatedAt(date);
			res.setLastUpdated(date);
			res.setSubjectId(newProject.getProjectid());
			res.setUpdatedBy(visa);

			resourceService.save(res);
		}

	}
}
